package api

import (
	"bytes"
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"go-caipu/pkg/api/helper"
	"go-caipu/pkg/api/jwt"
	"go-caipu/pkg/constant"
	"go-caipu/pkg/services/admin/sysuser"
	"go-caipu/pkg/services/storage/models"
	"go-caipu/pkg/util"
	"image/color"
	"io"
	"math/rand"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"go-caipu/pkg/infra/avatarbuilder"
	"go-caipu/pkg/infra/avatarbuilder/calc"
)

const (
	// Module 默认密码
	Module = "用户管理"
)

// @Tags 用户管理
// @Summary user manage
// @Description 分页查询用户
// @Accept json
// @Param Authorization header string true "用户授权auth key"
// @Param nickname query string false "用户昵称"
// @Param deptid query string false "部门id"
// @Param status query string false "状态"
// @Param phone query string false "手机号"
// @Param email query string false "邮箱"
// @Param CreateTime query string false "查询时间数组"
// @Success 200 {object} helper.Page
// @Router /system/user [get]
func (hs *HTTPServer) GetUserPage(c *gin.Context) {
	cmd := sysuser.GetUserPageCommand{}
	roleId := c.Param("roleId") //查询角色
	if roleId != "" {
		cmd.RoleIds = []string{roleId}
	}
	roleId = c.Query("roleId") //查询角色
	if roleId != "" {
		cmd.NoExcludeRoleUser = []string{roleId}
	}
	cmd.ExcludedRoleIds = c.QueryArray("excludeRoleIds") //排除角色 fix:插件使用
	if err := helper.BindAndValidate(c, &cmd, binding.Form); err != nil {
		return
	}
	if len(cmd.CreateTime) > 0 {
		cmd.BeginTime = cmd.CreateTime[0]
		cmd.EndTime = cmd.CreateTime[1]
	}

	if cmd.DeptId == "0" {
		cmd.DeptId = ""
	}
	result, count, err := hs.userService.GetUserPage(c.Request.Context(), cmd)

	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(c, helper.Page{CurrentPage: cmd.PageIndex, PageSize: cmd.PageSize, List: result, Total: count})
}

// GetUserOptions 提供用户选择
func (hs *HTTPServer) GetUserOptions(c *gin.Context) {
	cmd := sysuser.GetUserRequest{}
	if err := helper.BindAndValidate(c, &cmd, binding.Form); err != nil {
		return
	}

	result, err := hs.userService.GetUserByWhere(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(c, result)
}

// GetUser 编辑获取用户信息
func (hs *HTTPServer) GetUser(c *gin.Context) {
	cmd := sysuser.GetUserCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	result, err := hs.userService.GetUser(c.Request.Context(), cmd)

	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}

	helper.SuccessWithData(c, result)
}

// GetUserDetail 获取用户部分信息
func (hs *HTTPServer) GetUserDetail(c *gin.Context) {
	cmd := sysuser.GetUserCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	result, err := hs.userService.GetUser(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}

	helper.SuccessWithData(c, sysuser.WorkUserInfo{Avatar: result.Avatar, ID: result.UserId, Name: result.NickName, DeptId: result.DeptId})
}

// CreateUser sysuser create
func (hs *HTTPServer) CreateUser(c *gin.Context) {

	form := sysuser.InsertUserCommand{}
	if err := helper.BindAndValidate(c, &form); err != nil {
		return
	}
	form.UserId = hs.Snowflake.Generate().Int64()
	//生成临时图像
	path, err := createUserAvatar(form.UserId, form.NickName)
	if err == nil {
		// 打开文件
		file, err := os.Open(path)
		defer file.Close()
		if err != nil {
			helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInvalidParams, err)
			return
		}

		result := &models.FileStorage{
			FileName: file.Name(),
			FileSize: 0,
		}
		//如果图片保存失败，删除临时文件
		err = hs.storageService.Upload(context.Background(), result, file)
		if err == nil {
			form.Avatar = fmt.Sprintf("/api/file/%s", result.FileKey)
		} else {
			form.Avatar = "http://www.gocpu.cn/logo.png"
			app, _ := os.Getwd()
			path = filepath.Join(app, path)
			os.Remove(path) //删除临时文件
		}
	}

	form.Email = strings.TrimSpace(form.Email)
	form.Username = strings.TrimSpace(form.Username)
	form.Password = strings.TrimSpace(form.Password)

	form.CreateBy = hs.getJwtUserID(c)
	form.CreateUserString = hs.getUserName(form.CreateBy)
	if len(form.Password) < 6 {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("password is too short"))
		return
	}
	err = hs.userService.Create(c.Request.Context(), form)

	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

// 生成用户头像
func createUserAvatar(userId int64, nickName string) (tempPath string, err error) {
	var colors = []uint32{
		0xff6200, 0x42c58e, 0x5a8de1, 0x785fe0,
	}
	// 初始化随机数种子
	rand.Seed(time.Now().UnixNano())

	// 生成一个 0 到 3 之间的随机整数
	randomIndex := rand.Intn(len(colors))
	path, _ := os.Getwd()
	// init avatarbuilder, you need to tell builder ttf file and how to alignment text
	font := filepath.Join(path, "/resources/font/SourceHanSansSC-Medium.ttf")
	ab := avatarbuilder.NewAvatarBuilder(font, &calc.SourceHansSansSCMedium{})
	ab.SetBackgroundColorHex(colors[randomIndex])
	ab.SetFrontgroundColor(color.White)
	ab.SetFontSize(80)
	ab.SetAvatarSize(200, 200)
	// generate avatar image and save to file
	dir := "./data/temp"
	_ = util.EnsureDirExists(dir)
	filename := fmt.Sprintf("avatar_%d.png", userId)
	tempSave := filepath.Join(dir, filename)
	if err := ab.GenerateImageAndSave(getlastUserName(nickName), tempSave); err != nil {
		return "", err
	}
	return tempSave, nil
}
func getlastUserName(nickName string) string {
	// 将字符串转换为 rune 切片
	runeStr := []rune(nickName)
	// 获取字符串的长度
	length := len(runeStr)
	if length >= 2 {
		// 从后面取 2 个字符
		return string(runeStr[length-2:])

	} else {
		return nickName
	}
}
func (hs *HTTPServer) UpdateUser(c *gin.Context) {
	cmd := sysuser.UpdateUserCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}

	err := hs.userService.Update(c.Request.Context(), cmd)

	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

func (hs *HTTPServer) RemoveUser(c *gin.Context) {
	cmd := sysuser.RemoveUserCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	cmd.Id = c.Param("id")
	if cmd.Id != "" {
		intIds := make([]string, 0)
		strIds := strings.Split(cmd.Id, ",")
		for _, id := range strIds {
			intIds = append(intIds, id)
		}
		cmd.Ids = intIds
	}
	err := hs.userService.Remove(c.Request.Context(), cmd)

	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

// @Tags 用户管理
// @Summary 更新用户密码
// @Description 更新指定用户的密码
// @Accept json
// @Param Authorization header string true "用户授权auth key"
// @Param oldPassword formData string true "旧密码"
// @Param newPassword formData string true "新密码"
// @Success 200 {object} helper.Response "成功更新密码"
// @Failure 500 {object} helper.Response "服务器内部错误"
// @Router /api/user/profile/password [patch]
func (hs *HTTPServer) UpdateUserPwd(c *gin.Context) {
	cmd := sysuser.UpdatePwdCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	claims, err := hs.Jwt.ParseToken(c.Request.Header.Get(jwt.AUTH))
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	cmd.OldPassword = hs.Cfg.DecryptedData(cmd.OldPassword)
	cmd.NewPassword = hs.Cfg.DecryptedData(cmd.NewPassword)
	cmd.UserId = claims.UserId

	err = hs.userService.UpdateUserPwd(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}

func (hs *HTTPServer) ResetUserPwd(c *gin.Context) {
	cmd := sysuser.ResetPasswordCommand{}
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	cmd.Password = hs.Cfg.DecryptedData(cmd.Password)
	err := hs.userService.ResetUpdatePwd(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}
func getUserIdByToken(hs *HTTPServer, c *gin.Context) (int64, error) {
	tokenString := c.Request.Header.Get(jwt.AUTH)
	if tokenString == "" {
		return 0, errors.New(" no token")
	}
	userId, err := hs.Jwt.GetUserId(tokenString)
	if err != nil {
		return 0, errors.New("未正常获取到用户登录信息")
	}
	return userId, nil
}

// GetUserInfo  获取用户信息
func (hs *HTTPServer) GetUserInfo(c *gin.Context) {
	userId, err := getUserIdByToken(hs, c)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	cmd := sysuser.GetUserCommand{UserId: userId}
	user, err := hs.userService.GetUser(c.Request.Context(), cmd)

	//获取角色权限
	permission := []string{"*:*:*"}
	if !util.Contains(user.RoleIds, "1828271398028574720") {
		result, err2 := hs.roleService.GetPermissionByRole(user.RoleIds)
		if err2 != nil {
			helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err2)
			return
		}
		permission = result
	}
	result := AcroUserInfo{
		Id:               user.UserId,
		Phone:            user.Phone,
		Gender:           user.Sex,
		Email:            user.Email,
		Roles:            user.RoleNames,
		DeptId:           user.DeptId,
		DeptName:         user.DeptName,
		PwdExpired:       false, //check pwd expired
		PwdResetTime:     time.Now(),
		RegistrationDate: user.CreatedAt,
		Permissions:      permission,
		NickName:         user.NickName,
		UserName:         user.Username,
		//PwdResetTime:     sysuser.UpdatedAt,
	}
	//1、直接是标准url路径
	if strings.HasPrefix(user.Avatar, "http://") || strings.HasPrefix(user.Avatar, "https://") {
		result.Avatar = urlToBase64(user.Avatar)
		helper.SuccessWithData(c, result)
		return
	}
	//2、本地上传文件相对路径
	filepath := strings.Split(user.Avatar, "/")
	if len(filepath) > 1 {
		fileId := filepath[len(filepath)-1]

		file, storage, err := hs.storageService.DownLoad(c.Request.Context(), fileId)
		//获取文件失败
		if err != nil {
			result.Avatar = urlToBase64("https://doc.gocpu.cn/logo.png")
			helper.SuccessWithData(c, result)
			return
		}
		defer file.Close()
		result.Avatar = readCloserToBase64(file, storage.FileName)
	}
	helper.SuccessWithData(c, result)
}

type AcroUserInfo struct {
	Id               int64     `json:"id,string"`
	UserName         string    `json:"username"`
	NickName         string    `json:"nickname"`
	Avatar           string    `json:"avatar"`
	DeptId           int64     `json:"deptId"`
	DeptName         string    `json:"deptName"`
	Email            string    `json:"email"`
	Phone            string    `json:"phone"`
	Gender           int       `json:"gender"`
	PwdExpired       bool      `json:"pwdExpired"`
	PwdResetTime     time.Time `json:"pwdResetTime"`
	RegistrationDate string    `json:"registrationDate"`
	Roles            []string  `json:"roles"`
	Permissions      []string  `json:"permissions"`
	Description      string    `json:"description"`
}

func urlToBase64(url string) string {
	// 发起HTTP请求获取图片
	resp, err := http.Get(url)
	if err != nil {
		return ""
	}
	defer resp.Body.Close()

	// 检查响应状态
	if resp.StatusCode != http.StatusOK {
		return ""
	}

	// 从URL中提取文件扩展名
	ext := filepath.Ext(url)
	if ext == "" {
		// 如果没有扩展名，尝试从Content-Type获取
		contentType := resp.Header.Get("Content-Type")
		if strings.HasPrefix(contentType, "image/") {
			ext = "." + strings.TrimPrefix(contentType, "image/")
		} else {
			ext = ".jpg" // 默认使用jpg
		}
	}
	extWithoutDot := ext[1:]

	// 读取内容并编码
	var buffer bytes.Buffer
	_, err = io.Copy(&buffer, resp.Body)
	if err != nil {
		return ""
	}

	base64Encoded := base64.StdEncoding.EncodeToString(buffer.Bytes())
	return fmt.Sprintf("data:image/%s;base64,%s", extWithoutDot, base64Encoded)
}

// UpdateAvatarHandler 上传用户头像
func (hs *HTTPServer) UpdateAvatarHandler(c *gin.Context) {
	userId, err := getUserIdByToken(hs, c)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	//temp uploadFile
	file, err := c.FormFile("avatarFile")
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	reader, err := file.Open()
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	defer reader.Close()
	params := models.FileStorage{
		FileName: file.Filename,
		FileSize: file.Size,
	}
	err = hs.storageService.Upload(c.Request.Context(), &params, reader)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	model := sysuser.UpdateUserAvatarReq{Avatar: "/api/file/" + params.FileKey, UpdatedAt: time.Now(), UpdateBy: userId}

	err = hs.userService.UpdateAvatar(c.Request.Context(), model)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	avatar := makeImageBase64(file)
	helper.SuccessWithData(c, map[string]string{"avatar": avatar})
}
func makeImageBase64(uploadFile *multipart.FileHeader) string {
	file, err := uploadFile.Open()
	if err != nil {
		return ""
	}
	defer file.Close()

	avatar, err := io.ReadAll(file)
	if err != nil {
		return ""
	}
	ext := filepath.Ext(uploadFile.Filename)
	// 去除扩展名中的点
	extWithoutDot := ext[1:]
	return fmt.Sprintf("data:image/%s;base64,%s", extWithoutDot, base64.StdEncoding.EncodeToString(avatar))
}
func readCloserToBase64(rc io.ReadCloser, fileName string) string {
	// 创建一个缓冲区来存储读取的内容
	var buffer bytes.Buffer
	_, err := io.Copy(&buffer, rc)
	if err != nil {
		return ""
	}
	// 将缓冲区的内容转换为 base64 编码的字符串
	ext := filepath.Ext(fileName)
	// 去除扩展名中的点
	extWithoutDot := ext[1:]
	base64Encoded := base64.StdEncoding.EncodeToString(buffer.Bytes())
	return fmt.Sprintf("data:image/%s;base64,%s", extWithoutDot, base64Encoded)
}

// UpdateUserRoleHandler 更新用户角色
func (hs *HTTPServer) UpdateUserRoleHandler(c *gin.Context) {
	currUserId, err := getUserIdByToken(hs, c)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}

	var cmd sysuser.UpdateUserRole
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	cmd.UpdateUserId = util.Int64ToString(currUserId)
	//cmd.UserId = util.StringToInt64(c.Param("userId"))
	err = hs.userService.UpdateUserRole(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}
func (hs *HTTPServer) UpdateUserBasicInfoHandler(c *gin.Context) {
	currUserId, err := getUserIdByToken(hs, c)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	var cmd sysuser.UpdateUserBasicInfoReq
	if err := helper.BindAndValidate(c, &cmd); err != nil {
		return
	}
	cmd.UserId = currUserId
	err = hs.userService.UpdateUserBasicInfo(c.Request.Context(), cmd)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithOutData(c)
}
